macos: plug leak of application windows
authorChristian Hergert <chergert@redhat.com>
Thu, 3 Dec 2020 03:42:07 +0000 (19:42 -0800)
committerChristian Hergert <chergert@redhat.com>
Thu, 3 Dec 2020 03:44:02 +0000 (19:44 -0800)
This ensures that we don't leak window references inside the action muxer.
Otherwise, we risk not disposing the windows upon gtk_window_destroy()
and blocking the main loop from quitting.

Fixes #3419

gtk/gtkapplication-quartz.c

index a744ebd89e50bb7204ab0ba39c470515eae0d0ab..5472c206416a5f183f5e82f4c5295de772e0da45 100644 (file)
@@ -250,12 +250,38 @@ gtk_application_impl_quartz_shutdown (GtkApplicationImpl *impl)
   quartz->inhibitors = NULL;
 }
 
+static void
+on_window_unmap_cb (GtkApplicationImpl *impl,
+                    GtkWindow          *window)
+{
+  GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
+
+  if ((GActionGroup *)window == gtk_action_muxer_get_group (quartz->muxer, "win"))
+    gtk_action_muxer_remove (quartz->muxer, "win");
+}
+
 static void
 gtk_application_impl_quartz_active_window_changed (GtkApplicationImpl *impl,
                                                    GtkWindow          *window)
 {
   GtkApplicationImplQuartz *quartz = (GtkApplicationImplQuartz *) impl;
 
+  /* Track unmapping of the window so we can clear the "win" field.
+   * Without this, we might hold on to a reference of the window
+   * preventing it from getting disposed.
+   */
+  if (window != NULL && !g_object_get_data (G_OBJECT (window), "quartz-muxer-umap"))
+    {
+      gulong handler_id = g_signal_connect_object (window,
+                                                   "unmap",
+                                                   G_CALLBACK (on_window_unmap_cb),
+                                                   impl,
+                                                   G_CONNECT_SWAPPED);
+      g_object_set_data (G_OBJECT (window),
+                         "quartz-muxer-unmap",
+                         GSIZE_TO_POINTER (handler_id));
+    }
+
   gtk_action_muxer_remove (quartz->muxer, "win");
 
   if (G_IS_ACTION_GROUP (window))